package model;

import java.util.Map;
import java.util.Random;

/**
 * Process class for the simulator.
 * @author Son Pham & Sydney Lin
 * @version 2.0
 */
public abstract class Process
{
  /**
   * The max offset value from the base of my_max_step range.
   */
  public static final int RANGE_OFFSET = 501;
  
  /**
   * The base of my_max_step range.
   */
  public static final int RANGE_BASE = 500;
  
  /**
   * My program counter.
   */
  private int my_pc;
  
  /**
   * My max number of steps.
   */
  private int my_max_step;
  
  /**
   * My status.
   */
  private Status my_status;
  
  /**
   * The number of actions in this process.
   * Note: for Producer and Consumer this will be the number of pairs of up and down 
   * on semaphores.
   */
  private int my_num_action;
  
  /**
   * The map of <step, action>.
   */
  private Map<Integer, ProcessAction> my_action_map;
  
  /**
   * Name of this process.
   */
  private String my_name;
  
  /**
   * Construct a process.
   */
  public Process(final String the_name)
  {
    final Random rand = new Random();    
    // my_max_step is ranging from 500 to 1000 inclusively.
    my_max_step = RANGE_BASE + rand.nextInt(RANGE_OFFSET);
    // my_num_action is ranging from 15 to 25 inclusively.
    my_num_action = rand.nextInt(50) + 50;
    my_pc = 0;
    my_status = Status.READY;
    my_name = the_name;
  }
  
  /**
   * 
   * @return The program counter.
   */
  public int getPC()
  {
    return my_pc;
  }
  
  /**
   * Set the program counter of this process.
   * @param the_pc The PC.
   */
  private void setPC(final int the_pc)
  {
    my_pc = the_pc;
  }
  
  /**
   * Advance the PC. If the PC reach the max step, PC will restart with 0.
   */
  public void advancePC()
  {
    if (my_pc + 1 > my_max_step)
    {
      my_pc = 0;
    }
    else
    {
      my_pc++;
    }
  }
  
  /**
   * 
   * @return The number of actions of this process.
   */
  public int getNumAction()
  {
    return my_num_action;
  }
  
  /**
   * 
   * @return The max number of steps.
   */
  public int getMaxStep()
  {   
    //System.out.print("the max step: " + my_max_step + "\n");
    return my_max_step;
  }
  
  /**
   * 
   * @return Set the max number of steps.
   */
  /**
  public void setMaxStep()
  { 
    int the_max_step = 0;
    Set<Integer> set = my_table.keySet();
    for(Object o : set)
    {
      if((Integer)o > the_max_step)
      {
         the_max_step = (Integer)o;
      }
        
    }
    my_max_step = the_max_step;

  }*/
  
  /**
   * 
   * @return The status.
   */
  public Status getStatus()
  {
    return my_status;
  }
  
  /**
   * Set the status of this process.
   * @param the_status The status.
   */
  public void setStatus(final Status the_status)
  {
    my_status = the_status;
  }
  
  /**
   * @return The action map of <step, action> for this process.
   */
  public Map<Integer, ProcessAction> getActionMap()
  {
    return my_action_map;
  }
  
  /**
   * 
   * @param the_map The map of <step, action>.
   */
  public void setActionMap(final Map<Integer, ProcessAction> the_map)
  {
    my_action_map = the_map;    
  }
  
  /**
   * 
   * @return The action at this PC.
   */
  public ProcessAction getAction()
  {
    if (my_action_map.containsKey(my_pc))
    {
      return my_action_map.get(my_pc);
    }
    else
    {
      return ProcessAction.NO_ACTION;
    }
  }
  
  /**
   * @return The name of this process.
   */
  public String toString()
  {
    return my_name;
  }
}
